"""
全局异常处理机制
"""

import asyncio
import traceback
from typing import Dict, Any, Optional, Callable
from fastapi import Request, Response, HTTPException
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
import time

from ...core.logging import get_logger, audit_logger
from ...core.config import settings
from .base import (
    AppException,
    BusinessException,
    ValidationError,
    NotFoundError,
    AuthenticationError,
    AuthorizationError,
    RateLimitError,
    ExternalServiceError,
    DatabaseError,
    CacheError,
    ConfigurationError
)

logger = get_logger(__name__)


class ExceptionContext:
    """异常上下文"""
    
    def __init__(self):
        self.request_id: Optional[str] = None
        self.user_id: Optional[str] = None
        self.endpoint: Optional[str] = None
        self.method: Optional[str] = None
        self.client_ip: Optional[str] = None
        self.user_agent: Optional[str] = None
        self.timestamp: float = time.time()
        self.extra_data: Dict[str, Any] = {}
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "request_id": self.request_id,
            "user_id": self.user_id,
            "endpoint": self.endpoint,
            "method": self.method,
            "client_ip": self.client_ip,
            "user_agent": self.user_agent,
            "timestamp": self.timestamp,
            "extra_data": self.extra_data
        }


class ExceptionHandler:
    """异常处理器"""
    
    def __init__(self):
        self.handlers: Dict[type, Callable] = {}
        self.error_callbacks: List[Callable[[Exception, ExceptionContext], None]] = []
        
        # 注册默认处理器
        self._register_default_handlers()
    
    def register_handler(self, exception_type: type, handler: Callable):
        """注册异常处理器"""
        self.handlers[exception_type] = handler
        logger.debug(f"Registered handler for {exception_type.__name__}")
    
    def add_error_callback(self, callback: Callable[[Exception, ExceptionContext], None]):
        """添加错误回调"""
        self.error_callbacks.append(callback)
    
    async def handle_exception(
        self,
        exception: Exception,
        request: Optional[Request] = None
    ) -> Dict[str, Any]:
        """处理异常"""
        # 创建异常上下文
        context = self._create_context(request)
        
        try:
            # 查找处理器
            handler = self._find_handler(exception)
            
            # 执行处理器
            if handler:
                result = await self._execute_handler(handler, exception, context)
            else:
                result = await self._default_handler(exception, context)
            
            # 记录异常
            await self._log_exception(exception, context, result)
            
            # 执行错误回调
            await self._execute_error_callbacks(exception, context)
            
            return result
            
        except Exception as handler_error:
            logger.error(f"Exception handler failed: {handler_error}")
            return {
                "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Internal server error",
                    "details": "An unexpected error occurred while handling the exception"
                },
                "request_id": context.request_id
            }
    
    def _find_handler(self, exception: Exception) -> Optional[Callable]:
        """查找异常处理器"""
        exception_type = type(exception)
        
        # 精确匹配
        if exception_type in self.handlers:
            return self.handlers[exception_type]
        
        # 子类匹配
        for registered_type, handler in self.handlers.items():
            if issubclass(exception_type, registered_type):
                return handler
        
        return None
    
    async def _execute_handler(
        self,
        handler: Callable,
        exception: Exception,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """执行异常处理器"""
        try:
            if asyncio.iscoroutinefunction(handler):
                return await handler(exception, context)
            else:
                return handler(exception, context)
        except Exception as e:
            logger.error(f"Exception handler execution failed: {e}")
            return await self._default_handler(exception, context)
    
    async def _default_handler(
        self,
        exception: Exception,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """默认异常处理器"""
        if isinstance(exception, AppException):
            return {
                "error": {
                    "code": exception.error_code,
                    "message": str(exception),
                    "details": exception.details or {}
                },
                "request_id": context.request_id
            }
        
        elif isinstance(exception, HTTPException):
            return {
                "error": {
                    "code": f"HTTP_{exception.status_code}",
                    "message": exception.detail,
                    "details": {}
                },
                "request_id": context.request_id
            }
        
        elif isinstance(exception, RequestValidationError):
            return {
                "error": {
                    "code": "VALIDATION_ERROR",
                    "message": "Request validation failed",
                    "details": {
                        "validation_errors": exception.errors()
                    }
                },
                "request_id": context.request_id
            }
        
        else:
            # 未处理的异常
            logger.error(f"Unhandled exception: {exception}\n{traceback.format_exc()}")
            return {
                "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Internal server error",
                    "details": {}
                },
                "request_id": context.request_id
            }
    
    def _create_context(self, request: Optional[Request]) -> ExceptionContext:
        """创建异常上下文"""
        context = ExceptionContext()
        
        if request:
            context.request_id = getattr(request.state, "request_id", None)
            context.user_id = getattr(request.state, "user_id", None)
            context.endpoint = str(request.url.path)
            context.method = request.method
            context.client_ip = self._get_client_ip(request)
            context.user_agent = request.headers.get("user-agent")
            
            # 额外的请求数据
            context.extra_data = {
                "query_params": dict(request.query_params),
                "path_params": dict(request.path_params)
            }
        
        return context
    
    def _get_client_ip(self, request: Request) -> str:
        """获取客户端IP"""
        # 检查代理头
        forwarded_for = request.headers.get("x-forwarded-for")
        if forwarded_for:
            return forwarded_for.split(",")[0].strip()
        
        real_ip = request.headers.get("x-real-ip")
        if real_ip:
            return real_ip
        
        # 回退到客户端地址
        return request.client.host if request.client else "unknown"
    
    async def _log_exception(
        self,
        exception: Exception,
        context: ExceptionContext,
        result: Dict[str, Any]
    ):
        """记录异常日志"""
        error_code = result.get("error", {}).get("code", "UNKNOWN")
        
        # 记录应用日志
        if isinstance(exception, (ValidationError, NotFoundError)):
            logger.warning(
                f"Application error: {error_code} - {str(exception)}",
                extra={
                    "exception_type": type(exception).__name__,
                    "context": context.to_dict(),
                    "error_code": error_code
                }
            )
        elif isinstance(exception, (DatabaseError, CacheError)):
            logger.error(
                f"System error: {error_code} - {str(exception)}",
                extra={
                    "exception_type": type(exception).__name__,
                    "context": context.to_dict(),
                    "error_code": error_code
                }
            )
        elif isinstance(exception, AppException):
            logger.info(
                f"Business error: {error_code} - {str(exception)}",
                extra={
                    "exception_type": type(exception).__name__,
                    "context": context.to_dict(),
                    "error_code": error_code
                }
            )
        else:
            logger.error(
                f"Unexpected error: {error_code} - {str(exception)}\n{traceback.format_exc()}",
                extra={
                    "exception_type": type(exception).__name__,
                    "context": context.to_dict(),
                    "error_code": error_code
                }
            )
        
        # 记录审计日志
        if context.user_id:
            audit_logger.log_user_action(
                user_id=context.user_id,
                action="error_occurred",
                resource=context.endpoint or "unknown",
                details={
                    "error_code": error_code,
                    "error_message": str(exception),
                    "request_id": context.request_id,
                    "client_ip": context.client_ip
                }
            )
    
    async def _execute_error_callbacks(
        self,
        exception: Exception,
        context: ExceptionContext
    ):
        """执行错误回调"""
        for callback in self.error_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(exception, context)
                else:
                    callback(exception, context)
            except Exception as e:
                logger.error(f"Error callback failed: {e}")
    
    def _register_default_handlers(self):
        """注册默认处理器"""
        # AppException 处理器
        self.register_handler(AppException, self._handle_app_exception)
        
        # HTTPException 处理器
        self.register_handler(HTTPException, self._handle_http_exception)
        
        # RequestValidationError 处理器
        self.register_handler(RequestValidationError, self._handle_validation_error)
        
        # StarletteHTTPException 处理器
        self.register_handler(StarletteHTTPException, self._handle_starlette_http_exception)
    
    async def _handle_app_exception(
        self,
        exception: AppException,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """处理应用异常"""
        return {
            "error": {
                "code": exception.error_code,
                "message": str(exception),
                "details": exception.details or {}
            },
            "request_id": context.request_id
        }
    
    async def _handle_http_exception(
        self,
        exception: HTTPException,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """处理HTTP异常"""
        return {
            "error": {
                "code": f"HTTP_{exception.status_code}",
                "message": exception.detail,
                "details": {}
            },
            "request_id": context.request_id
        }
    
    async def _handle_validation_error(
        self,
        exception: RequestValidationError,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """处理验证错误"""
        return {
            "error": {
                "code": "VALIDATION_ERROR",
                "message": "Request validation failed",
                "details": {
                    "validation_errors": exception.errors()
                }
            },
            "request_id": context.request_id
        }
    
    async def _handle_starlette_http_exception(
        self,
        exception: StarletteHTTPException,
        context: ExceptionContext
    ) -> Dict[str, Any]:
        """处理Starlette HTTP异常"""
        return {
            "error": {
                "code": f"HTTP_{exception.status_code}",
                "message": exception.detail,
                "details": {}
            },
            "request_id": context.request_id
        }


# 全局异常处理器实例
exception_handler = ExceptionHandler()


# FastAPI异常处理中间件
async def exception_middleware(request: Request, call_next):
    """异常处理中间件"""
    try:
        response = await call_next(request)
        return response
    except Exception as exception:
        # 处理异常
        error_response = await exception_handler.handle_exception(exception, request)
        
        # 确定HTTP状态码
        status_code = 500
        
        if isinstance(exception, HTTPException):
            status_code = exception.status_code
        elif isinstance(exception, (ValidationError, RequestValidationError)):
            status_code = 422
        elif isinstance(exception, NotFoundError):
            status_code = 404
        elif isinstance(exception, AuthenticationError):
            status_code = 401
        elif isinstance(exception, AuthorizationError):
            status_code = 403
        elif isinstance(exception, RateLimitError):
            status_code = 429
        elif isinstance(exception, AppException):
            # 根据异常类型确定状态码
            if isinstance(exception, ValidationError):
                status_code = 422
            elif isinstance(exception, NotFoundError):
                status_code = 404
            elif isinstance(exception, AuthenticationError):
                status_code = 401
            elif isinstance(exception, AuthorizationError):
                status_code = 403
            elif isinstance(exception, RateLimitError):
                status_code = 429
        
        # 返回JSON响应
        from fastapi.responses import JSONResponse
        return JSONResponse(
            status_code=status_code,
            content=error_response
        )


# 便捷函数
async def handle_async_exception(exception: Exception) -> Dict[str, Any]:
    """处理异步异常（便捷函数）"""
    return await exception_handler.handle_exception(exception)


def add_exception_callback(callback: Callable[[Exception, ExceptionContext], None]):
    """添加异常回调（便捷函数）"""
    exception_handler.add_error_callback(callback)


def register_exception_handler(exception_type: type, handler: Callable):
    """注册异常处理器（便捷函数）"""
    exception_handler.register_handler(exception_type, handler)


# 装饰器
def exception_handler_decorator(exception_types: list = None):
    """异常处理装饰器"""
    if exception_types is None:
        exception_types = [Exception]
    
    def decorator(func):
        async def wrapper(*args, **kwargs):
            try:
                if asyncio.iscoroutinefunction(func):
                    return await func(*args, **kwargs)
                else:
                    return func(*args, **kwargs)
            except Exception as e:
                # 检查是否在指定异常类型中
                for exception_type in exception_types:
                    if isinstance(e, exception_type):
                        return await handle_async_exception(e)
                
                # 如果不匹配，重新抛出异常
                raise
        
        return wrapper
    return decorator


# 上下文管理器
class ExceptionContextManager:
    """异常上下文管理器"""
    
    def __init__(self, context_data: Dict[str, Any] = None):
        self.context_data = context_data or {}
        self.start_time = time.time()
    
    async def __aenter__(self):
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if exc_type and exc_val:
            # 记录异常
            await handle_async_exception(exc_val)
            
            # 记录执行时间
            execution_time = time.time() - self.start_time
            
            logger.info(
                f"Exception caught in context manager: {exc_type.__name__}",
                extra={
                    "execution_time": execution_time,
                    "context": self.context_data
                }
            )
        
        return True  # 不重新抛出异常


# 使用示例：
# async with ExceptionContextManager({"operation": "file_upload"}):
#     # 可能抛出异常的代码
#     await risky_operation()
